//	Copyright (c) 2008, x-port.net ltd.
//
//	All rights reserved.
//
//	Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
//	    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//	    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//	    * Neither the name of the x-port.net ltd. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
//	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//	LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//	A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//	CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//	PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//	LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//   Purpose:  Internet utility function definitions..
//   $Id$


#include "stdafx.h"
#include <wininet.h>
#include <Common/InternetUtil.h>

// Read a file from an internet URL.
HRESULT xport::ReadFromInternet(const char *lpszURL, void **ppContent, DWORD &dwFileSize, const char *sHTTPUserName, const DWORD dwPacketSize, char **psContentType, char **psErrorString, unsigned long *pnProgress, DWORD *pdwHTTPCode)
{
	HRESULT hr = E_FAIL;

	unsigned long nProgress = 0;

	// Check the arguments.
	if(lpszURL && ppContent && dwPacketSize > 0 && sHTTPUserName) {
		++nProgress;
		// Open an internet connection.
		HINTERNET hInet = ::InternetOpen(CA2T(sHTTPUserName), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
		if(hInet) {
			++nProgress;
			// Connect to the supplied URL.
			HINTERNET hURL = ::InternetOpenUrl(hInet, CA2T(lpszURL), 0, 0, INTERNET_FLAG_NO_UI | INTERNET_FLAG_RESYNCHRONIZE, 0);
			if(hURL) {
				++nProgress;
				DWORD dwCode, dwSize = sizeof(DWORD), dwIndex = 0;
				// Check the connection.
				if(::HttpQueryInfo(hURL, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwCode, &dwSize, &dwIndex) == TRUE && dwCode == 200) {
					++nProgress;
					// Allocate initial block of memory for the file content.
					*ppContent = ::malloc(dwPacketSize);
					DWORD dwBytesRead = 0;
					bool bDone = false;
					
					// Sequentially read the file.
					while(!bDone && *ppContent) {
						DWORD dw = 0;
						BOOL b = ::InternetReadFile(hURL, reinterpret_cast<BYTE*>(*ppContent) + dwBytesRead, dwPacketSize, &dw);
						dwBytesRead += dw;
						if(dw != dwPacketSize)
						{
							// The whole file has now been read.
							bDone = true;
							// Won't write to cache until InternetReadFile returns 0 bytes read.
							BYTE b;
							::InternetReadFile(hURL, &b, 1, &dw);
						}
						else
							// Allocate more memory for the next iteration.
							*ppContent = ::realloc(*ppContent, dwBytesRead + dwPacketSize);
					}
					if(*ppContent) {
						dwFileSize = dwBytesRead;
						*(reinterpret_cast<BYTE*>(*ppContent) + dwBytesRead) = 0;
						hr = S_OK;
					} else
						hr = E_OUTOFMEMORY;
				} else if(psErrorString) {
					DWORD dwError = ::GetLastError();
					::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, 0, (LPTSTR)psErrorString, 0, 0);
				}

				if(pdwHTTPCode)
					*pdwHTTPCode = dwCode;

				if(psContentType) {
					++nProgress;
					DWORD dwBufLen = 256, dwIndex = 0;
					char sContentType[257];
					if(::HttpQueryInfo(hURL, HTTP_QUERY_CONTENT_TYPE, reinterpret_cast<void *>(sContentType), &dwBufLen, &dwIndex) == TRUE && dwBufLen > 0) {
						*psContentType = reinterpret_cast<char *>(malloc(dwBufLen + 1));
						if(*psContentType) {
							memcpy(*psContentType, sContentType, dwBufLen);
							(*psContentType)[dwBufLen] = '\0';
						}
					} else if(psErrorString) {
						DWORD dwError = ::GetLastError();
						::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, 0, (LPTSTR)psErrorString, 0, 0);
					}
				}
				::InternetCloseHandle(hURL);
			} else if(psErrorString) {
				DWORD dwError = ::GetLastError();
				::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, 0, (LPTSTR)psErrorString, 0, 0);
			}
			::InternetCloseHandle(hInet);
		} else if(psErrorString) {
			DWORD dwError = ::GetLastError();
			::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, 0, (LPTSTR)psErrorString, 0, 0);
		}
	} else
		hr = E_INVALIDARG;

	if(pnProgress)
		*pnProgress = nProgress;

	return hr;
}

// Check whether an internet connection is open.
bool xport::IsInternetConnectionOpen(void)
{
	// Assume that we have a connection.
	bool bConnected = true;

	DWORD dwConnectionFlags;
	BOOL bConnectionExists = InternetGetConnectedState(&dwConnectionFlags, 0);

	// If there is no internet connection, or the system is in offline mode...
	if(bConnectionExists == FALSE || dwConnectionFlags & INTERNET_CONNECTION_OFFLINE)
		// ...we have no connection.
		bConnected = false;

	return bConnected;
}
